﻿using System;
using System.Drawing;
using System.Windows.Forms;
using KinectCore.Gui.Controller;
using SurveySystem.Factory;
using SurveySystem.GUI.Forms;
using SurveySystem.Model;
using xn;

namespace SurveySystem
{
    public delegate void SurveyFinishedEvent();
    /// <summary>
    /// Class to control the execution of the survey
    /// </summary>
    public class SurveyController
    {

        public readonly Color[] activeColors = new Color[] { Color.FromArgb(250, 0, 0), Color.FromArgb(200, 0, 0), Color.FromArgb(150, 0, 0), Color.FromArgb(100, 0, 0), Color.FromArgb(50, 0, 0), Color.FromArgb(0, 0, 0), };

        private enum QuestionPanelOptions { REFRESH, RESET, HIDE, POPULATE };

        #region " Member vars "
        // Kinect stuff
        //private Context context;
        //private MouseEmulatorController hands;

        // Survey Finished Event
        public event SurveyFinishedEvent SurveyFinished;

        // GUI stuff
        public SurveyMainForm MainForm { get; private set; }
        private SurveyWelcomePanel welcomePanel;
        private SurveyQuestionPanel questionPanel;
        private SurveyCompletePanel completePanel;

        // survey vars
        private ResultFactory factory;
        private Survey Survey;
        private int questionIndex;
        private Response SurveyResponse;

        // Timer vars
        System.Timers.Timer timer;
        int timeLimit = 3000;
        int elapsedTime = 0;

        /// <summary>
        /// The array of responses (possible answers) selected
        /// </summary>
        private bool[] responsesSelected = new bool[] { false, false, false, false, false, false };

        // Active control
        private Control activeControl;

        // Active Screen
        private UserControl activeScreen;

        #endregion

        #region " Constructors "
        public SurveyController(SurveyMainForm mainForm, Context ctx, Survey survey, ResultFactory factory)
        {
            // init kinect stuff
            //this.context = ctx;
            //this.hands = new MouseEmulatorController(ctx);
            // init survey stuff
            this.Survey = survey;
            this.factory = factory;
            this.questionIndex = -1;

            // init the gui stuff
            MainForm = mainForm;
            MainForm.FormClosed += new System.Windows.Forms.FormClosedEventHandler(MainForm_FormClosed);
            System.Windows.Media.Color backgroundColor = Survey.BackgroundColor;
            MainForm.ThemeBackColor = Color.FromArgb(backgroundColor.A, backgroundColor.R, backgroundColor.G, backgroundColor.B);
            System.Windows.Media.Color foregroundColor = Survey.ForegroundColor;
            MainForm.ThemeForeColor = Color.FromArgb(foregroundColor.A, foregroundColor.R, foregroundColor.G, foregroundColor.B);

            // create the welcome panel
            welcomePanel = new SurveyWelcomePanel();
            MainForm.ConvertToTheme(welcomePanel.Controls);

            // add handlers for the start button
            welcomePanel.btnStart.Click += new System.EventHandler(welcomePanel_btnStart_Click);
            welcomePanel.btnStart.MouseEnter += new EventHandler(welcomePanel_btnStart_MouseEnter);
            welcomePanel.btnStart.MouseLeave += new EventHandler(control_MouseLeave);

            // create the survey panel
            questionPanel = new SurveyQuestionPanel();

            // add handlers for the back button
            questionPanel.btnBack.Click += new System.EventHandler(questionPanel_btnBack_Click);
            questionPanel.btnBack.MouseEnter += new EventHandler(questionPanel_AnyButton_MouseEnter);
            questionPanel.btnBack.MouseLeave += new EventHandler(questionPanel_btnBack_MouseLeave);

            // add handlers for the next button
            questionPanel.btnNext.Click += new System.EventHandler(questionPanel_btnNext_Click);
            questionPanel.btnNext.MouseEnter += new EventHandler(questionPanel_AnyButton_MouseEnter);
            questionPanel.btnNext.MouseLeave += new EventHandler(questionPanel_btnNext_MouseLeave);

            // add handlers for the exit button
            questionPanel.btnExit.Click += new EventHandler(questionPanel_btnExit_Click);
            questionPanel.btnExit.MouseEnter += new EventHandler(questionPanel_AnyButton_MouseEnter);
            questionPanel.btnExit.MouseLeave += new EventHandler(questionPanel_btnExit_MouseLeave);

            // add handlers for the option 1 button
            questionPanel.ansOption1.btnSelect.MouseEnter += new EventHandler(questionPanel_AnyButton_MouseEnter);
            questionPanel.ansOption1.btnSelect.MouseLeave += new EventHandler(control_MouseLeave);
            questionPanel.ansOption1.btnSelect.Click += new EventHandler(questionPanel_AnswerButton_Click);

            // add handlers for the option 2 button
            questionPanel.ansOption2.btnSelect.MouseEnter += new EventHandler(questionPanel_AnyButton_MouseEnter);
            questionPanel.ansOption2.btnSelect.MouseLeave += new EventHandler(control_MouseLeave);
            questionPanel.ansOption2.btnSelect.Click += new EventHandler(questionPanel_AnswerButton_Click);

            // add handlers for the option 3 button
            questionPanel.ansOption3.btnSelect.MouseEnter += new EventHandler(questionPanel_AnyButton_MouseEnter);
            questionPanel.ansOption3.btnSelect.MouseLeave += new EventHandler(control_MouseLeave);
            questionPanel.ansOption3.btnSelect.Click += new EventHandler(questionPanel_AnswerButton_Click);

            // add handlers for the option 4 button
            questionPanel.ansOption4.btnSelect.MouseEnter += new EventHandler(questionPanel_AnyButton_MouseEnter);
            questionPanel.ansOption4.btnSelect.MouseLeave += new EventHandler(control_MouseLeave);
            questionPanel.ansOption4.btnSelect.Click += new EventHandler(questionPanel_AnswerButton_Click);

            // add handlers for the option 5 button
            questionPanel.ansOption5.btnSelect.MouseEnter += new EventHandler(questionPanel_AnyButton_MouseEnter);
            questionPanel.ansOption5.btnSelect.MouseLeave += new EventHandler(control_MouseLeave);
            questionPanel.ansOption5.btnSelect.Click += new EventHandler(questionPanel_AnswerButton_Click);

            // add handlers for the option 6 button
            questionPanel.ansOption6.btnSelect.MouseEnter += new EventHandler(questionPanel_AnyButton_MouseEnter);
            questionPanel.ansOption6.btnSelect.MouseLeave += new EventHandler(control_MouseLeave);
            questionPanel.ansOption6.btnSelect.Click += new EventHandler(questionPanel_AnswerButton_Click);

            // convert question panel controls to survey theme
            MainForm.ConvertToTheme(questionPanel.Controls);
            MainForm.ConvertToTheme(questionPanel.ansOption1);
            MainForm.ConvertToTheme(questionPanel.ansOption2);
            MainForm.ConvertToTheme(questionPanel.ansOption3);
            MainForm.ConvertToTheme(questionPanel.ansOption4);
            MainForm.ConvertToTheme(questionPanel.ansOption5);
            MainForm.ConvertToTheme(questionPanel.ansOption6);


            // setup the complete panel
            completePanel = new SurveyCompletePanel();
            completePanel.btnReturnToStart.MouseEnter += new EventHandler(questionPanel_AnyButton_MouseEnter);
            completePanel.btnReturnToStart.MouseLeave += new EventHandler(completePanel_btnReturnToStart_MouseLeave);
            completePanel.btnReturnToStart.Click += new EventHandler(completePanel_btnReturnToStart_Click);

            completePanel.btnExit.MouseEnter += new EventHandler(questionPanel_AnyButton_MouseEnter);
            completePanel.btnExit.MouseLeave += new EventHandler(completePanel_btnExit_MouseLeave);
            completePanel.btnExit.Click += new EventHandler(completePanel_btnExit_Click);

            MainForm.ConvertToTheme(completePanel.Controls);

            // hide all of the answers
            hideOptions();

            // init num of responses to 0
            responsesSelected[0] = responsesSelected[1] = responsesSelected[2] = responsesSelected[3] = responsesSelected[4] = responsesSelected[5] = false;

            // add handler for the activated control
            //hands.ControlActivated += new ControlActivatedEvent(hands_ControlActivated);

            // set the active screen to be the welcome panel
            activeScreen = welcomePanel;

        }
        
        #endregion

        #region " Control Timers "

        /// <summary>
        /// Stops the timer and sets the text on the active control
        /// </summary>
        /// <param name="text">The text to display on the active control</param>
        void stopTimer(string text)
        {
            timer.Stop();
            elapsedTime = 0;

            // if the active control is not null update the text of the control and set the active control to null
            if (activeControl != null)
            {
                activeControl.Invoke(new UpdateTextCallback(this.UpdateText), new Object[] { text });
                activeControl = null;
            }
        }

        /// <summary>
        /// Starts the timer
        /// </summary>
        void startTimer()
        {
            timer = new System.Timers.Timer(1000);
            // add a handler for when the time elapses
            timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
            elapsedTime = 0;
            timer.Start();
        }

        /// <summary>
        /// Handles when the time elapses
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">Event args</param>
        void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            // increae the elapsed time
            elapsedTime++;
            // update the text on the active to control to the elapsed time
            activeControl.Invoke(new UpdateTextCallback(this.UpdateText), new object[] { elapsedTime.ToString() });

            // if the elapsed time reaches the time limit activate the control
            if (elapsedTime * 1000 == timeLimit)
            {
                ControlActivated(activeControl);
            }
        }
        #endregion

        #region " Button Click Event Handlers "

        #region " WelcomePanel "
        /// <summary>
        /// Handles when the welcome panel's next button is clicked
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">Event args</param>
        void welcomePanel_btnStart_Click(object sender, System.EventArgs e)
        {
            // handle the button start click
            welcomePanel.Invoke(new UpdateWelcomeScreenCallback(this.UpdateWelcomeScreen));

            SurveyResponse = null;
        }

        /// <summary>
        /// Handles when the mouse enters the welcome panel's start button
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">Event args</param>
        void welcomePanel_btnStart_MouseEnter(object sender, EventArgs e)
        {
            // set the start button to be the active control
            activeControl = welcomePanel.btnStart;
            startTimer();
        }
        #endregion

        #region " Question Panel "
        /// <summary>
        /// Handles when the mouse leaves the question panel's next button
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">Event args</param>
        void questionPanel_btnNext_MouseLeave(object sender, EventArgs e)
        {
            // stop the timer and set the text accordingly
            stopTimer((questionIndex == Survey.Questions.Count - 1) ? "Submit" : "Next >>");
        }

        /// <summary>
        /// Handles when the mouse enters the question panel's next button
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">Event args</param>
        void questionPanel_AnyButton_MouseEnter(object sender, EventArgs e)
        {
            // set the next button to be the active control
            activeControl = (Control)sender;
            startTimer();
        }

        /// <summary>
        /// Handles when the mouse leaves the question panel's back button
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">Event args</param>
        void questionPanel_btnBack_MouseLeave(object sender, EventArgs e)
        {
            // stop the timer and set the text accordingly
            stopTimer("<< Back");
        }

        /// <summary>
        /// Handles when the question panel's next button is clicked
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">Event args</param>
        void questionPanel_btnNext_Click(object sender, System.EventArgs e)
        {
            // call the leave button function
            questionPanel_btnNext_MouseLeave(null, null);

            RecordQuestionResult();

            // show the next question
            showQuestion(++questionIndex);
        }

        /// <summary>
        /// Handles when the question panel's exit button is clicked
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">Event args</param>
        void questionPanel_btnExit_Click(object sender, System.EventArgs e)
        {
            questionPanel.Invoke(new SurveyFinishedCallback(this.IndicateSurveyFinished));
        }

        /// <summary>
        /// Handles when the mouse leaves the question panel's exit button
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">Event args</param>
        void questionPanel_btnExit_MouseLeave(object sender, System.EventArgs e)
        {
            // stop the timer and set the text accordingly
            stopTimer("Exit");
        }

        /// <summary>
        /// Handles when an answer button is selected on the question panel
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">Event args</param>
        void questionPanel_AnswerButton_Click(object sender, EventArgs e)
        {
            if (sender == questionPanel.ansOption1.btnSelect)
            {
                // stop the timer
                stopTimer("");

                SelectResponse(1);
            }
            else if (sender == questionPanel.ansOption2.btnSelect)
            {
                // stop the timer
                stopTimer("");

                SelectResponse(2);
            }
            else if (sender == questionPanel.ansOption3.btnSelect)
            {
                // stop the timer
                stopTimer("");

                SelectResponse(3);
            }
            else if (sender == questionPanel.ansOption4.btnSelect)
            {
                // stop the timer
                stopTimer("");

                SelectResponse(4);
            }
            else if (sender == questionPanel.ansOption5.btnSelect)
            {
                // stop the timer
                stopTimer("");

                SelectResponse(5);
            }
            else if (sender == questionPanel.ansOption6.btnSelect)
            {
                // stop the timer
                stopTimer("");

                SelectResponse(6);
            }
        }

        /// <summary>
        /// Handles when the question panel's back button is clicked
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">Event args</param>
        void questionPanel_btnBack_Click(object sender, System.EventArgs e)
        {
            // call the leave button function
            questionPanel_btnBack_MouseLeave(null, null);

            RecordQuestionResult();

            // show the previous question
            showQuestion(--questionIndex);
        }
        
        #endregion

        #region " Complete Panel "

        /// <summary>
        /// Handles when the mouse leaves the complete panel's back to start button
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">Event args</param>
        void completePanel_btnReturnToStart_MouseLeave(object sender, EventArgs e)
        {
            stopTimer("Back to Start");
        }

        /// <summary>
        /// Handles when the mouse leaves the question panel's exit button
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">Event args</param>
        void completePanel_btnExit_MouseLeave(object sender, EventArgs e)
        {
            stopTimer("Exit");
        }

        /// <summary>
        /// Restarts the Survey
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void completePanel_btnReturnToStart_Click(object sender, EventArgs e)
        {
            ShowSurveyWelcome();
        }

        /// <summary>
        /// Throws a Survey Complete Event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void completePanel_btnExit_Click(object sender, EventArgs e)
        {
            SurveyFinished();
        }

        #endregion


        #region " General "
        /// <summary>
        /// Handles when the mouse leaves a control
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">Event args</param>
        void control_MouseLeave(object sender, EventArgs e)
        {
            // stop the timer and set the text to "Select"
            stopTimer("Select");
        }

        /// <summary>
        /// Handles when a control is activated
        /// </summary>
        /// <param name="c">The control that is activated</param>
        private void ControlActivated(Control c)
        {
            if (c == null)
                return;

            Console.WriteLine("Control Activated");

            if (c == welcomePanel.btnStart)
            {
                welcomePanel_btnStart_Click(null, null);
            }
            else if (c == questionPanel.btnNext)
            {
                questionPanel_btnNext_Click(null, null);
            }
            else if (c == questionPanel.btnBack)
            {
                questionPanel_btnBack_Click(null, null);
            }
            else if (c == questionPanel.btnExit)
            {
                questionPanel_btnExit_Click(null, null);
            }
            else if (c == questionPanel.ansOption1.btnSelect)
            {
                questionPanel_AnswerButton_Click(c, null);
            }
            else if (c == questionPanel.ansOption2.btnSelect)
            {
                questionPanel_AnswerButton_Click(c, null);
            }
            else if (c == questionPanel.ansOption3.btnSelect)
            {
                questionPanel_AnswerButton_Click(c, null);
            }
            else if (c == questionPanel.ansOption4.btnSelect)
            {
                questionPanel_AnswerButton_Click(c, null);
            }
            else if (c == questionPanel.ansOption5.btnSelect)
            {
                questionPanel_AnswerButton_Click(c, null);
            }
            else if (c == questionPanel.ansOption6.btnSelect)
            {
                questionPanel_AnswerButton_Click(c, null);
            }
            else if (c == completePanel.btnReturnToStart)
            {
                completePanel_btnReturnToStart_Click(null, null);
            }
            else if (c == completePanel.btnExit)
            {
                completePanel_btnExit_Click(null, null);
            }
        }

        #endregion

        #endregion

        #region " ** DELETE THIS ** Other GUI Event Handlers "

        /// <summary>
        /// Handles when the form is closed
        /// </summary>
        /// <param name="sender">The sender</param>
        /// <param name="e">Event args</param>
        void MainForm_FormClosed(object sender, System.Windows.Forms.FormClosedEventArgs e)
        {
            // stop tracking the hands
            //hands.Stop();

            //// dispose of the context
            //context.Dispose();
        }

        /// <summary>
        /// Handles when a control is activated
        /// </summary>
        /// <param name="c"></param>
        void hands_ControlActivated(System.Windows.Forms.Control c)
        {
            // activate the control
            ControlActivated(c);
        }

        /// <summary>
        /// Handles when the hands control leaves
        /// </summary>
        /// <param name="c">The control</param>
        void hands_ControlLeave(System.Windows.Forms.Control c)
        {
            // reset the control's colour (in case something's gone wrong and we're not looking at the same control)
            c.BackColor = System.Drawing.SystemColors.Control;
        }



        #endregion

        #region " Survey Navigation methods "

        /// <summary>
        /// Shows the welcome survey
        /// </summary>
        public void ShowSurveyWelcome()
        {

            if (Survey == null)
            {
                // DO NOTHING
            }
            else
            {
                lock (Survey)
                {
                    // display the details of the survey
                    welcomePanel.lblTitle.Text = Survey.Title;
                    welcomePanel.lblDescription.Text = Survey.Description;
                    welcomePanel.lblSurveyBy.Text = Survey.Owner;
                    welcomePanel.lblMoreInfo.Text = Survey.MoreInfoUrl;
                    welcomePanel.lblNumQuestions.Text = Survey.Questions.Count.ToString();
                }
            }

            MainForm.Invoke(new ShowInitialWelcomeScreenCallback(this.ShowInitWelcomeScreen));

            // setup the active controls on this form
            //hands.ParentControl = welcomePanel;
            //hands.AddControl(welcomePanel.btnStart);

            // clear any responses
            SurveyResponse = null;



            // debugging
            //welcomePanel.btnStart.Visible = false;
        }

        /// <summary>
        /// Delegate to show the initial welcome screen
        /// </summary>
        private delegate void ShowInitialWelcomeScreenCallback();

        /// <summary>
        /// Shows question [<paramref name="index"/>]
        /// </summary>
        /// <param name="index"></param>
        public void showQuestion(int index)
        {
            // if the question index is out of range, set it to -1
            if (index < -1)
            {
                index = -1;
            }

            // goto survey welcome screen if questionIndex is -1
            if (index == -1)
            {
                ShowSurveyWelcome();
                return;
            }

            if (Survey == null)
            {
                // DO NOTHING
            }
            else
            {
                lock (Survey)
                {
                    if (index > Survey.Questions.Count - 1)
                    {
                        factory.SubmitResults(Survey, SurveyResponse);

                        MainForm.Invoke(new ShowSurveyConclusionCallback(this.showSurveyConclusion));

                        return;
                    }

                    // resets the screen
                    questionPanel.Invoke(new UpdateQuestionScreenCallback(this.UpdateQuestionScreen), new Object[] { QuestionPanelOptions.RESET, questionIndex });
                    // hides all options
                    questionPanel.Invoke(new UpdateQuestionScreenCallback(this.UpdateQuestionScreen), new Object[] { QuestionPanelOptions.HIDE, questionIndex });
                    // shows valid options
                    questionPanel.Invoke(new UpdateQuestionScreenCallback(this.UpdateQuestionScreen), new Object[] { QuestionPanelOptions.POPULATE, questionIndex });

                }
            }

        }


        private void showSurveyConclusion()
        {
            // remove any other controls from main form
            MainForm.Controls.Clear();
            // add the welcome panel and make visible
            completePanel.Dock = System.Windows.Forms.DockStyle.Fill;
            completePanel.lblTitle.Text = Survey.Title;

            MainForm.Controls.Add(completePanel);
            MainForm.Visible = true;


            // setup the active controls on this form
            //hands.ParentControl = completePanel;
            //hands.AddControl(completePanel.btnReturnToStart);

            // clear any responses
            SurveyResponse = null;

        }

        private void RecordQuestionResult()
        {
            // RECORD RESULT
            // 1 - see if we have a response object already created
            if (SurveyResponse == null)
            {
                SurveyResponse = new Response();
                SurveyResponse.SurveyID = Survey.SurveyID;
                SurveyResponse.Machine = Environment.MachineName;
            }
            // 2 - Remove any answers for the current question already in the response object
            for (int i = 0; i < SurveyResponse.Answers.Count; i++)
            {
                if (SurveyResponse.Answers[i].QuestionID == Survey.Questions[questionIndex].QuestionID)
                {
                    SurveyResponse.Answers.RemoveAt(i);
                    i--;
                }
            }
            // 3 - Add new ResponseAnswer object(s) for each of the selection(s)
            for (int i = 0; i < Survey.Questions[questionIndex].PossibleAnswers.Count; i++)
            {
                // if this response has been selected, create a new ResponseAnswer object in the Response object
                if (responsesSelected[i])
                {
                    ResponseAnswer ra = new ResponseAnswer();
                    ra.QuestionID = Survey.Questions[questionIndex].QuestionID;
                    ra.AnswerID = Survey.Questions[questionIndex].PossibleAnswers[i].AnswerID;
                    SurveyResponse.Answers.Add(ra);
                }
            }
        }

        #endregion

        #region " GUI Threading Workarounds "

        /// <summary>
        /// Delegate to indicate that the user has finished the survey
        /// </summary>
        private delegate void SurveyFinishedCallback();

        /// <summary>
        /// Method to indicate that the user has finsihed the survey
        /// </summary>
        private void IndicateSurveyFinished()
        {
            SurveyFinished();
        }

        /// <summary>
        /// Delegate to update text on a control
        /// </summary>
        /// <param name="text">The text to display on the active control</param>
        private delegate void UpdateTextCallback(string text);

        /// <summary>
        /// Updates the text on the active control
        /// </summary>
        /// <param name="text">The text to display on the active control</param>
        private void UpdateText(string text)
        {
            activeControl.Text = text;
        }

        /// <summary>
        /// Delegate to show the survey conclusion screen
        /// </summary>
        private delegate void ShowSurveyConclusionCallback();

        /// <summary>
        /// Shows the initial welcome screen
        /// </summary>
        private void ShowInitWelcomeScreen()
        {
            // remove any other controls from main form
            MainForm.Controls.Clear();
            // add the welcome panel and make visible
            welcomePanel.Dock = System.Windows.Forms.DockStyle.Fill;
            MainForm.Controls.Add(welcomePanel);
            MainForm.Visible = true;
        }


        /// <summary>
        /// Delegate to update the welcome screen
        /// </summary>
        private delegate void UpdateWelcomeScreenCallback();

        /// <summary>
        /// Updates the welcome screen
        /// </summary>
        private void UpdateWelcomeScreen()
        {
            // remove any other controls from main form
            MainForm.Controls.Clear();
            // add the welcome panel and make visible
            questionPanel.Dock = System.Windows.Forms.DockStyle.Fill;
            MainForm.Controls.Remove(welcomePanel);
            MainForm.Controls.Add(questionPanel);
            MainForm.Visible = true;

            // show the first question
            questionIndex = 0;
            showQuestion(questionIndex);

        }

        /// <summary>
        /// Delegate to update the question screen
        /// </summary>
        /// <param name="operation">The operation to perform</param>
        /// <param name="questionIndex">The current question</param>
        private delegate void UpdateQuestionScreenCallback(QuestionPanelOptions operation, int questionIndex);

        /// <summary>
        /// Updates the question screen
        /// </summary>
        /// <param name="operation">The operation to perform</param>
        /// <param name="questionIndex">The current question</param>
        private void UpdateQuestionScreen(QuestionPanelOptions operation, int questionIndex)
        {
            switch (operation)
            {
                case QuestionPanelOptions.RESET:
                    reloadQuestionResponses();
                    break;
                case QuestionPanelOptions.HIDE:
                    hideOptions();
                    break;
                case QuestionPanelOptions.POPULATE:
                    populateOptions(questionIndex);
                    break;
                case QuestionPanelOptions.REFRESH:
                    // do nothing
                    break;
                default:
                    break;
            }

            // update the display state of all the buttons
            questionPanel.ansOption1.btnSelect.Text = responsesSelected[0] ? "Selected" : "Select";
            questionPanel.ansOption1.btnSelect.BackColor = responsesSelected[0] ? Color.LightGreen : questionPanel.ansOption1.ButtonBackColor;
            questionPanel.ansOption2.btnSelect.Text = responsesSelected[1] ? "Selected" : "Select";
            questionPanel.ansOption2.btnSelect.BackColor = responsesSelected[1] ? Color.LightGreen : questionPanel.ansOption1.ButtonBackColor;
            questionPanel.ansOption3.btnSelect.Text = responsesSelected[2] ? "Selected" : "Select";
            questionPanel.ansOption3.btnSelect.BackColor = responsesSelected[2] ? Color.LightGreen : questionPanel.ansOption1.ButtonBackColor;
            questionPanel.ansOption4.btnSelect.Text = responsesSelected[3] ? "Selected" : "Select";
            questionPanel.ansOption4.btnSelect.BackColor = responsesSelected[3] ? Color.LightGreen : questionPanel.ansOption1.ButtonBackColor;
            questionPanel.ansOption5.btnSelect.Text = responsesSelected[4] ? "Selected" : "Select";
            questionPanel.ansOption5.btnSelect.BackColor = responsesSelected[4] ? Color.LightGreen : questionPanel.ansOption1.ButtonBackColor;
            questionPanel.ansOption6.btnSelect.Text = responsesSelected[5] ? "Selected" : "Select";
            questionPanel.ansOption6.btnSelect.BackColor = responsesSelected[5] ? Color.LightGreen : questionPanel.ansOption1.ButtonBackColor;

            questionPanel.btnNext.Text = (questionIndex == Survey.Questions.Count - 1) ? "Submit" : "Next >>";
            questionPanel.btnBack.Visible = (questionIndex != 0);

        }

        /// <summary>
        /// Resets all the options
        /// </summary>
        private void reloadQuestionResponses()
        {
            // reset all answers (we'll set them later if needed)
            responsesSelected[0] = responsesSelected[1] = responsesSelected[2] = responsesSelected[3] = responsesSelected[4] = responsesSelected[5] = false;


            // 1 - see if we have a response object already created
            if (SurveyResponse == null)
            {
                // if not, there'll be no answers
                return;
            }

            // see if we have any ResponseAnswers in our Response object
            // Wouldn't it be great if I knew enough LINQ to tidy this up? - PSK
            foreach (ResponseAnswer ra in SurveyResponse.Answers)
            {
                if (ra.QuestionID == Survey.Questions[questionIndex].QuestionID)
                {
                    // this is an answer to the question - figure out which answer it is

                    for (int q = 0; q < Survey.Questions[questionIndex].PossibleAnswers.Count; q++)
                    {
                        if (Survey.Questions[questionIndex].PossibleAnswers[q].AnswerID == ra.AnswerID)
                        {
                            // flag this answer
                            responsesSelected[q] = true;
                            break; // break out of for (int q...) loop
                        }
                    }
                }
            }


        }

        /// <summary>
        /// Hides all of the options
        /// </summary>
        private void hideOptions()
        {
            questionPanel.ansOption1.Visible = false;
            questionPanel.ansOption2.Visible = false;
            questionPanel.ansOption3.Visible = false;
            questionPanel.ansOption4.Visible = false;
            questionPanel.ansOption5.Visible = false;
            questionPanel.ansOption6.Visible = false;
        }

        /// <summary>
        /// Populates the options
        /// </summary>
        /// <param name="questionIndex">The current question</param>
        private void populateOptions(int questionIndex)
        {

            // populate labels
            Question q = Survey.Questions[questionIndex];
            questionPanel.lblQuestion.Text = q.QuestionText;
            questionPanel.lblQuestionNum.Text = "Question " + (questionIndex + 1).ToString() + " of " + Survey.Questions.Count.ToString();
            questionPanel.lblSurveyTitle.Text = Survey.Title;
            questionPanel.lblSelectOneMany.Text = q.MultiSelect ? "Select ALL that apply" : "Select ONE";

            // populate answers
            if (q.PossibleAnswers.Count > 0)
            {
                questionPanel.ansOption1.Text = q.PossibleAnswers[0].AnswerText;
                questionPanel.ansOption1.Visible = true;
            }

            if (q.PossibleAnswers.Count > 1)
            {
                questionPanel.ansOption2.Text = q.PossibleAnswers[1].AnswerText;
                questionPanel.ansOption2.Visible = true;
            }

            if (q.PossibleAnswers.Count > 2)
            {
                questionPanel.ansOption3.Text = q.PossibleAnswers[2].AnswerText;
                questionPanel.ansOption3.Visible = true;
            }

            if (q.PossibleAnswers.Count > 3)
            {
                questionPanel.ansOption4.Text = q.PossibleAnswers[3].AnswerText;
                questionPanel.ansOption4.Visible = true;
            }

            if (q.PossibleAnswers.Count > 4)
            {
                questionPanel.ansOption5.Text = q.PossibleAnswers[4].AnswerText;
                questionPanel.ansOption5.Visible = true;
            }

            if (q.PossibleAnswers.Count > 5)
            {
                questionPanel.ansOption6.Text = q.PossibleAnswers[5].AnswerText;
                questionPanel.ansOption6.Visible = true;
            }
        }

        /// <summary>
        /// Selects a response (possible answer). The response is toggled on or off if multi-select, or the selection overrides any other if not multi-select
        /// </summary>
        /// <param name="response">The 1-based index of the response to be selected</param>
        private void SelectResponse(int response)
        {
            if (Survey.Questions[questionIndex].MultiSelect)
            {
                // if multi-select, toggle the response
                if (response >= 0 && response < responsesSelected.Length)
                    responsesSelected[response - 1] = !responsesSelected[response - 1];
            }
            else
            {
                // if not multi-select, set all to false, then set the appropriate one to trie
                responsesSelected[0] = responsesSelected[1] = responsesSelected[2] = responsesSelected[3] = responsesSelected[4] = responsesSelected[5] = false;
                if (response >= 0 && response < responsesSelected.Length)
                    responsesSelected[response - 1] = true;
            }

            // update the display state of all the buttons
            questionPanel.Invoke(new UpdateQuestionScreenCallback(this.UpdateQuestionScreen), new Object[] { QuestionPanelOptions.REFRESH, questionIndex });
        }

        #endregion

    }

}
